#include <rtthread.h>
#include <rtdevice.h>
#include <stm32f4xx_dma.h>
#include <stm32f4xx_spi.h>
#include <stm32f4xx_rcc.h>
#include <rthw.h>
#include <misc.h>
#include "./drv_spi.h"

#define LOG_TAG "drv.spi"   /* 模块TAG */
#define LOG_LVL LOG_LVL_DBG /* 静态过滤级别 */
#include <ulog.h>           /* 必须放在宏定义下面 */

/* 
*   SPI速度很快,如果使用中断接收，则花了大量时间在中断的出栈入栈上，因此不考虑中断方式发送接收
*   若发送接收一个使用DMA，另一个不是用DMA，依旧需要花费时间在标志的查询等待上，因此发送接收的DMA方式需统一
*/

struct stm32_spi_dma
{
    DMA_Stream_TypeDef *dma_stream; /* DMA流 */
    uint32_t dma_ch;                /* DMA通道号 */
    uint32_t dma_flag;              /* DMA中断标志 */
    IRQn_Type dma_irq_ch;           /* DMA中断号 */
};

struct stm32_hw_spi_cs
{
    GPIO_TypeDef *GPIOx;
    uint16_t GPIO_Pin;
}; /* SPI设备片选脚 */

/* stm32 spi dirver class */
struct stm32_spi
{
    SPI_TypeDef *spi;                      /* SPI硬件结构体 */
    const char *bus_name;                  /* 总线名称 */
    char dma_flag;                         /* 发送接收方式 */
    struct rt_spi_bus spi_bus;             /* SPI总线结构体 */
    struct rt_spi_configuration *cfg;      /* 总线参数配置 */
    struct stm32_spi_dma *tx_dma, *rx_dma; /* 发送接收用DMA */
    struct rt_completion tx_completion;    /* 用来指示DMA是否发送完成 */
    struct rt_completion tx_rx_completion; /* 用来指示DMA是否发送接收完成，SPI的特性，需要通过发送数据来实现接收 */
    char tx_rx_flag;                       /* 指示当前是否既有发送又有接收 */
};

static rt_err_t spi_configure(struct rt_spi_device *device,
                              struct rt_spi_configuration *configuration);
static rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configuration *cfg);
static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message);

static void stm32_transmit(struct stm32_spi *spi_drv, const void *buf, rt_size_t length);
static void stm32_receive(struct stm32_spi *spi_drv, void *buf, rt_size_t length);
static rt_size_t stm32_transmit_dma(struct stm32_spi *spi_drv, const void *buf, rt_size_t length);
static rt_size_t stm32_receive_dma(struct stm32_spi *spi_drv, void *buf, rt_size_t length);
static rt_size_t stm32_spi_dma(DMA_Stream_TypeDef *dma_stream, rt_uint8_t data_width, const void *data, rt_size_t data_length);
static void stm32_spi_dma_init(struct stm32_spi *spi_drv);
static void stm32_dma_done(struct stm32_spi *spi_drv, char is_tx);

__STATIC_INLINE void CS_Set(struct stm32_hw_spi_cs *cs)
{
    cs->GPIOx->BSRRL = cs->GPIO_Pin;
}
__STATIC_INLINE void CS_Clear(struct stm32_hw_spi_cs *cs) { cs->GPIOx->BSRRH = cs->GPIO_Pin; }

void stm32_transmit(struct stm32_spi *spi_drv, const void *buf, rt_size_t length)
{

    /* 当前使用查询方式发送接收 */
    if (8 == spi_drv->cfg->data_width)
    {
        const rt_int8_t *send_data = (rt_int8_t *)buf;
        while (length)
        {
            while (!(spi_drv->spi->SR & SPI_I2S_FLAG_TXE))
                ;                          /* 等待TXE置1 */
            spi_drv->spi->DR = *send_data; /* 写入数据 */
            length--;
            send_data++;
        }
    }
    else
    {
        const rt_int16_t *send_data = (rt_int16_t *)buf;
        while (length)
        {
            while (!(spi_drv->spi->SR & SPI_I2S_FLAG_TXE))
                ;                          /* 等待TXE置1 */
            spi_drv->spi->DR = *send_data; /* 写入数据 */
            length--;
            send_data++;
        }
    }
}

void stm32_receive(struct stm32_spi *spi_drv, void *buf, rt_size_t length)
{
    if (8 == spi_drv->cfg->data_width)
    {
        uint8_t *recv_data = (uint8_t *)buf;
        while (length)
        {
            while (!(spi_drv->spi->SR & SPI_I2S_FLAG_RXNE))
                ;                                   /* 等待RXNE置1 */
            *recv_data = (spi_drv->spi->DR) & 0xFF; /* 读取数据 */
            length--;
            recv_data++;
        }
    }
    else
    {
        uint16_t *recv_data = (uint16_t *)buf;
        while (length)
        {
            while (!(spi_drv->spi->SR & SPI_I2S_FLAG_RXNE))
                ;                          /* 等待RXNE置1 */
            *recv_data = spi_drv->spi->DR; /* 读取数据 */
            length--;
            recv_data++;
        }
    }
}
rt_size_t stm32_transmit_dma(struct stm32_spi *spi_drv, const void *buf, rt_size_t length)
{
    return stm32_spi_dma(spi_drv->tx_dma->dma_stream, spi_drv->cfg->data_width, buf, length);
}
rt_size_t stm32_receive_dma(struct stm32_spi *spi_drv, void *buf, rt_size_t length)
{
    spi_drv->tx_rx_flag = 1;
    return stm32_spi_dma(spi_drv->rx_dma->dma_stream, spi_drv->cfg->data_width, buf, length);
}

rt_size_t stm32_spi_dma(DMA_Stream_TypeDef *dma_stream, rt_uint8_t data_width, const void *data, rt_size_t data_length)
{
    /*
	* 在stm32f4的手册中，DMA-SR寄存器说明下面有一句话
	* 将 EN 位置“1”以启动新传输之前， DMA_LISR 或 DMA_HISR 寄存器中与数据流相对应的事件标志必须清零
	*
	* 在传输结束前禁止数据流（EN位清零），会产生传输完成事件
	*/

    uint8_t x = 0;         //指示当前是哪个流，DMAy_Streamx
    uint32_t add_temp = 0; //保存需修改寄存器的地址
    uint32_t temp = 0;

    dma_stream->CR &= ~DMA_SxCR_EN; /* 关闭DMA */
    if (dma_stream < DMA2_Stream0)
    {
        x = ((uint32_t)dma_stream - (uint32_t)DMA1_Stream0) / 0x18; //获取当前流控制器
        add_temp = (uint32_t) & (DMA1->LIFCR) + (x & (0x04));       //保存寄存器地址
    }
    else
    {
        x = ((uint32_t)dma_stream - (uint32_t)DMA2_Stream0) / 0x18;
        add_temp = (uint32_t) & (DMA2->LIFCR) + (x & (0x04)); //保存寄存器地址
    }
    temp = (0x3D << (6 * (x & 0x01))) << ((x & 0x02) << 3);
    *(uint32_t *)add_temp = temp; //清除所有中断标志

    if (data_length > 65535)
    {
        data_length = 65535;
    }

    dma_stream->M0AR = (uint32_t)data; /* 设置内存空间 */
    dma_stream->NDTR = data_length;    /* 设置数据长度 */
    rt_uint32_t CR_temp = dma_stream->CR;
    CR_temp &= (~0x7800); /* 清除数据宽度寄存器 */
    if (8 == data_width)
    {
        CR_temp |= (DMA_MemoryDataSize_Byte | DMA_PeripheralDataSize_Byte);
    }
    else
    {
        CR_temp |= (DMA_MemoryDataSize_HalfWord | DMA_PeripheralDataSize_HalfWord);
    }
    dma_stream->CR = (CR_temp | DMA_SxCR_EN);

    return data_length;
}

void stm32_spi_dma_init(struct stm32_spi *spi_drv)
{
    if (spi_drv->tx_dma && spi_drv->rx_dma)
    {
        DMA_InitTypeDef DMA_InitStructure;

        spi_drv->dma_flag = 1;

        rt_completion_init(&spi_drv->tx_completion);
        rt_completion_init(&spi_drv->tx_rx_completion);

        /* 配置DMA */
        DMA_DeInit(spi_drv->tx_dma->dma_stream);
        DMA_DeInit(spi_drv->rx_dma->dma_stream);

        while (DMA_GetCmdStatus(spi_drv->tx_dma->dma_stream) != DISABLE)
            ;
        while (DMA_GetCmdStatus(spi_drv->rx_dma->dma_stream) != DISABLE)
            ;

        DMA_InitStructure.DMA_Channel = spi_drv->tx_dma->dma_ch;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (spi_drv->spi->DR);
        DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;
        DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
        DMA_InitStructure.DMA_BufferSize = 0;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
        DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
        DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
        DMA_Init(spi_drv->tx_dma->dma_stream, &DMA_InitStructure);

        DMA_InitStructure.DMA_Channel = spi_drv->rx_dma->dma_ch;
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & (spi_drv->spi->DR);
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
        DMA_Init(spi_drv->rx_dma->dma_stream, &DMA_InitStructure);

        /* 打开SPI DMA使能 */
        spi_drv->spi->CR2 |= (SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx);

        DMA_ClearFlag(spi_drv->tx_dma->dma_stream, spi_drv->tx_dma->dma_flag);
        DMA_ClearFlag(spi_drv->rx_dma->dma_stream, spi_drv->rx_dma->dma_flag);

        DMA_ITConfig(spi_drv->tx_dma->dma_stream, DMA_IT_TC, ENABLE);
        DMA_ITConfig(spi_drv->rx_dma->dma_stream, DMA_IT_TC, ENABLE);

        /* 配置DMA中断 */
        NVIC_InitTypeDef NVIC_InitStructure;

        NVIC_InitStructure.NVIC_IRQChannel = spi_drv->tx_dma->dma_irq_ch;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        NVIC_InitStructure.NVIC_IRQChannel = spi_drv->rx_dma->dma_irq_ch;
        NVIC_Init(&NVIC_InitStructure);
    }
    else
    {
        spi_drv->dma_flag = 0;
    }
}

void stm32_dma_done(struct stm32_spi *spi_drv, char is_tx)
{
    if (is_tx)
    {
        if (DMA_GetFlagStatus(spi_drv->tx_dma->dma_stream, spi_drv->tx_dma->dma_flag) != RESET)
        {
            DMA_ClearFlag(spi_drv->tx_dma->dma_stream, spi_drv->tx_dma->dma_flag);
            if (!spi_drv->tx_rx_flag)
            {
                rt_completion_done(&spi_drv->tx_completion);
            }
        }
    }
    else
    {
        if (DMA_GetFlagStatus(spi_drv->rx_dma->dma_stream, spi_drv->rx_dma->dma_flag) != RESET)
        {
            DMA_ClearFlag(spi_drv->rx_dma->dma_stream, spi_drv->rx_dma->dma_flag);
            if (spi_drv->tx_rx_flag)
            {
                spi_drv->tx_rx_flag = 0;
                rt_completion_done(&spi_drv->tx_rx_completion);
            }
        }
    }
}

rt_err_t spi_configure(struct rt_spi_device *device,
                       struct rt_spi_configuration *configuration)
{
    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(configuration != RT_NULL);

    struct stm32_spi *spi_drv = rt_container_of(device->bus, struct stm32_spi, spi_bus);
    spi_drv->cfg = configuration;

    return stm32_spi_init(spi_drv, spi_drv->cfg);
}

rt_err_t stm32_spi_init(struct stm32_spi *spi_drv, struct rt_spi_configuration *cfg)
{
    RT_ASSERT(spi_drv != RT_NULL);
    RT_ASSERT(cfg != RT_NULL);

    SPI_Cmd(spi_drv->spi, DISABLE);

    SPI_InitTypeDef SPI_InitStructure;

    if (cfg->mode & RT_SPI_SLAVE)
    {
        SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; /* 从SPI模式 */
    }
    else
    {
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master; /* 主SPI模式 */
    }

    if (cfg->mode & RT_SPI_3WIRE)
    {
        SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; /* 单线双向半双工 */
    }
    else
    {
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; /* 双线双向全双工 */
    }

    if (cfg->data_width == 8)
    {
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; /* 数据帧为8位 */
    }
    else if (cfg->data_width == 16)
    {
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; /* 数据帧为16位 */
    }
    else
    {
        return -RT_EIO;
    }

    if (cfg->mode & RT_SPI_CPHA)
    {
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; /* 第二个跳变沿数据被采样 */
    }
    else
    {
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; /* 第一个跳变沿数据被采样 */
    }

    if (cfg->mode & RT_SPI_CPOL)
    {
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; /* 空闲时为高电平 */
    }
    else
    {
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; /* 空闲时为低电平 */
    }

    if (cfg->mode & RT_SPI_NO_CS)
    {
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; /* NSS信号由软件控制 */
    }
    else
    {
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; /* NSS信号由软件控制 */
    }

    RCC_ClocksTypeDef Get_RCC_Clocks;
    RCC_GetClocksFreq(&Get_RCC_Clocks);
    uint32_t SPI_APB_CLOCK = Get_RCC_Clocks.PCLK2_Frequency;

    if (cfg->max_hz >= SPI_APB_CLOCK / 2)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    }
    else if (cfg->max_hz >= SPI_APB_CLOCK / 4)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    }
    else if (cfg->max_hz >= SPI_APB_CLOCK / 8)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    }
    else if (cfg->max_hz >= SPI_APB_CLOCK / 16)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
    }
    else if (cfg->max_hz >= SPI_APB_CLOCK / 32)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    }
    else if (cfg->max_hz >= SPI_APB_CLOCK / 64)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
    }
    else if (cfg->max_hz >= SPI_APB_CLOCK / 128)
    {
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
    }
    else
    {
        /*  min prescaler 256 */
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    }

    if (cfg->mode & RT_SPI_MSB)
    {
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
    }
    else
    {
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
    }
    SPI_InitStructure.SPI_CRCPolynomial = 0x0007;

    SPI_Init(spi_drv->spi, &SPI_InitStructure);
    SPI_TIModeCmd(spi_drv->spi, DISABLE);

    SPI_Cmd(spi_drv->spi, ENABLE);

    return RT_EOK;
}

rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
    rt_size_t already_send_length;
    rt_size_t send_length;
    const void *send_buf;
    void *recv_buf;

    RT_ASSERT(device != RT_NULL);
    RT_ASSERT(device->bus != RT_NULL);
    RT_ASSERT(device->bus->parent.user_data != RT_NULL);
    RT_ASSERT(message != RT_NULL);

    struct stm32_spi *spi_drv = rt_container_of(device->bus, struct stm32_spi, spi_bus);
    struct stm32_hw_spi_cs *cs = device->parent.user_data;

    if (message->cs_take)
    {
        CS_Clear(cs);
    }

    if (spi_drv->cfg->mode & RT_SPI_3WIRE)
    {
        /* 单线双向半双工 */
        SPI_BiDirectionalLineConfig(spi_drv->spi, SPI_Direction_Tx); /* 先发送 */
        send_buf = message->send_buf;
        send_length = message->length; /* 获取待发送字节数 */

        if (spi_drv->dma_flag)
        {
            /* 当前使用DMA发送接收 */
            while (send_length && send_buf)
            {
                already_send_length = stm32_transmit_dma(spi_drv, send_buf, send_length); /* 使用DMA发送 */
                rt_completion_wait(&spi_drv->tx_completion, RT_WAITING_FOREVER);          /* 等待发送完成 */

                send_length -= already_send_length; /* 计算剩下未发数据数量 */
                if (8 == spi_drv->cfg->data_width)
                {
                    send_buf = (rt_int8_t *)send_buf + already_send_length; /* 计算下一次发送的数据地址 */
                }
                else
                {
                    send_buf = (rt_int16_t *)send_buf + already_send_length; /* 计算下一次发送的数据地址 */
                }
            }
        }
        else
        {
            /* 当前使用查询方式发送 */
            stm32_transmit(spi_drv, send_buf, send_length);
        }
        /* 数据已经发送完成，等待SPI传输结束 */
        while (!(spi_drv->spi->SR & SPI_I2S_FLAG_TXE))
            ; /* 等待TXE置1 */
        while (spi_drv->spi->SR & SPI_I2S_FLAG_BSY)
            ; /* 等待BUSY清0 */

        SPI_BiDirectionalLineConfig(spi_drv->spi, SPI_Direction_Rx); /* 再接收 */
        recv_buf = message->recv_buf;
        send_length = message->length; /* 获取待接收字节数 */
        if (spi_drv->dma_flag)
        {
            /* 当前使用DMA接收 */
            while (send_length && recv_buf)
            {
                already_send_length = stm32_receive_dma(spi_drv, recv_buf, send_length); /* 使用DMA发送 */
                rt_completion_wait(&spi_drv->tx_rx_completion, RT_WAITING_FOREVER);      /* 等待发送完成 */

                send_length -= already_send_length; /* 计算剩下未发数据数量 */
                if (8 == spi_drv->cfg->data_width)
                {
                    recv_buf = (rt_int8_t *)recv_buf + already_send_length; /* 计算下一次发送的数据地址 */
                }
                else
                {
                    recv_buf = (rt_int16_t *)recv_buf + already_send_length; /* 计算下一次发送的数据地址 */
                }
            }
        }
        else
        {
            /* 当前使用查询方式接收 */
            stm32_receive(spi_drv, recv_buf, send_length);
        }

        SPI_BiDirectionalLineConfig(spi_drv->spi, SPI_Direction_Tx); /* 空闲状态为发送 */
    }
    else
    {
        /* 全双工发送 */
        send_buf = message->send_buf;
        recv_buf = message->recv_buf;
        send_length = message->length; /* 获取待接收字节数 */
        if (spi_drv->dma_flag)
        {
            /* 当前使用DMA发送接收 */
            if (send_buf && recv_buf)
            {
                /* 当前有发送有接收 */
                while (send_length)
                {
                    already_send_length = stm32_receive_dma(spi_drv, recv_buf, send_length);  /* 配置DMA接收 */
                    already_send_length = stm32_transmit_dma(spi_drv, send_buf, send_length); /* 使用DMA发送 */

                    rt_completion_wait(&spi_drv->tx_rx_completion, RT_WAITING_FOREVER); /* 等待接收完成 */

                    send_length -= already_send_length; /* 计算剩下未发数据数量 */
                    if (8 == spi_drv->cfg->data_width)
                    {
                        send_buf = (rt_int8_t *)send_buf + already_send_length; /* 计算下一次发送的数据地址 */
                        recv_buf = (rt_int8_t *)recv_buf + already_send_length; /* 计算下一次发送的数据地址 */
                    }
                    else
                    {
                        send_buf = (rt_int16_t *)send_buf + already_send_length; /* 计算下一次发送的数据地址 */
                        recv_buf = (rt_int16_t *)recv_buf + already_send_length; /* 计算下一次发送的数据地址 */
                    }
                }
            }
            else if (send_buf)
            {
                /* 只有发送 */
                while (send_length && send_buf)
                {
                    already_send_length = stm32_transmit_dma(spi_drv, send_buf, send_length); /* 使用DMA发送 */

                    rt_completion_wait(&spi_drv->tx_completion, RT_WAITING_FOREVER); /* 等待发送完成 */

                    send_length -= already_send_length; /* 计算剩下未发数据数量 */
                    if (8 == spi_drv->cfg->data_width)
                    {
                        send_buf = (rt_int8_t *)send_buf + already_send_length; /* 计算下一次发送的数据地址 */
                    }
                    else
                    {
                        send_buf = (rt_int16_t *)send_buf + already_send_length; /* 计算下一次发送的数据地址 */
                    }
                }
            }
            else
            {
                /* 只有接收 */
                while (send_length && recv_buf)
                {
                    if (8 == spi_drv->cfg->data_width)
                    {
                        rt_memset((rt_int8_t *)recv_buf, 0xFF, send_length); /* 将数值清为0xFF */
                    }
                    else
                    {
                        rt_memset((rt_int16_t *)recv_buf, 0xFFFF, send_length); /* 将数值清为0xFFFF */
                    }
                    already_send_length = stm32_receive_dma(spi_drv, recv_buf, send_length);  /* 配置DMA接收 */
                    already_send_length = stm32_transmit_dma(spi_drv, recv_buf, send_length); /* 使用DMA发送 */

                    rt_completion_wait(&spi_drv->tx_rx_completion, RT_WAITING_FOREVER); /* 等待接收完成 */

                    send_length -= already_send_length; /* 计算剩下未发数据数量 */
                    if (8 == spi_drv->cfg->data_width)
                    {
                        recv_buf = (rt_int8_t *)recv_buf + already_send_length; /* 计算下一次发送的数据地址 */
                    }
                    else
                    {
                        recv_buf = (rt_int16_t *)recv_buf + already_send_length; /* 计算下一次发送的数据地址 */
                    }
                }
            }
        }
        else
        {
            /* 当前使用查询方式发送接收 */
            if (8 == spi_drv->cfg->data_width)
            {
                const rt_int8_t *send_data = (rt_int8_t *)send_buf;
                rt_int8_t *recv_data = (rt_int8_t *)recv_buf;
                while (send_length)
                {
                    while (!(spi_drv->spi->SR & SPI_I2S_FLAG_TXE))
                        ;                          /* 等待TXE置1 */
                    spi_drv->spi->DR = *send_data; /* 写入数据 */
                    while (!(spi_drv->spi->SR & SPI_I2S_FLAG_RXNE))
                        ;                          /* 等待RXNE置1 */
                    *recv_data = spi_drv->spi->DR; /* 读取数据 */
                    send_length--;
                    send_data++;
                    recv_data++;
                }
            }
            else
            {
                const rt_int16_t *send_data = (rt_int16_t *)send_buf;
                rt_int16_t *recv_data = (rt_int16_t *)recv_buf;
                while (send_length)
                {
                    while (!(spi_drv->spi->SR & SPI_I2S_FLAG_TXE))
                        ;                          /* 等待TXE置1 */
                    spi_drv->spi->DR = *send_data; /* 写入数据 */
                    while (!(spi_drv->spi->SR & SPI_I2S_FLAG_RXNE))
                        ;                          /* 等待RXNE置1 */
                    *recv_data = spi_drv->spi->DR; /* 读取数据 */
                    send_length--;
                    send_data++;
                    recv_data++;
                }
            }
        }
        /* 数据已经发送完成，等待SPI传输结束 */
        while (!(spi_drv->spi->SR & SPI_I2S_FLAG_TXE))
            ; /* 等待TXE置1 */
        while (spi_drv->spi->SR & SPI_I2S_FLAG_BSY)
            ; /* 等待BUSY清0 */
              /* 先读DR,再读SR序列可清楚OVR错误 */
        rt_uint16_t temp = spi_drv->spi->DR;
        temp = spi_drv->spi->SR;
    }

    if (message->cs_release)
    {
        CS_Set(cs);
    }

    return message->length;
}

static const struct rt_spi_ops stm_spi_ops = {
    .configure = spi_configure,
    .xfer = spixfer,
};

#ifdef RT_USING_SPI1
struct stm32_spi_dma spi1_tx = {
    .dma_stream = DMA2_Stream3,
    .dma_ch = DMA_Channel_3,
    .dma_flag = DMA_FLAG_TCIF3,
    .dma_irq_ch = DMA2_Stream3_IRQn,
};

struct stm32_spi_dma spi1_rx = {
    .dma_stream = DMA2_Stream0,
    .dma_ch = DMA_Channel_3,
    .dma_flag = DMA_FLAG_TCIF0,
    .dma_irq_ch = DMA2_Stream0_IRQn,
};

struct stm32_spi spi1 = {
    .spi = SPI1,
    .bus_name = "spi1",
    .tx_dma = &spi1_tx,
    .rx_dma = &spi1_rx,
};

void DMA2_Stream3_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    stm32_dma_done(&spi1, 1);

    /* leave interrupt */
    rt_interrupt_leave();
}

void DMA2_Stream0_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    stm32_dma_done(&spi1, 0);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

#ifdef RT_USING_SPI2
struct stm32_spi_dma spi2_tx = {
    .dma_stream = DMA1_Stream4,
    .dma_ch = DMA_Channel_0,
    .dma_flag = DMA_FLAG_TCIF4,
    .dma_irq_ch = DMA1_Stream4_IRQn,
};

struct stm32_spi_dma spi2_rx = {
    .dma_stream = DMA1_Stream3,
    .dma_ch = DMA_Channel_0,
    .dma_flag = DMA_FLAG_TCIF3,
    .dma_irq_ch = DMA1_Stream3_IRQn,
};

struct stm32_spi spi2 = {
    .spi = SPI2,
    .bus_name = "spi2",
    .tx_dma = &spi2_tx,
    .rx_dma = &spi2_rx,
};

void DMA1_Stream4_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    stm32_dma_done(&spi2, 1);

    /* leave interrupt */
    rt_interrupt_leave();
}

void DMA1_Stream3_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    stm32_dma_done(&spi2, 0);

    /* leave interrupt */
    rt_interrupt_leave();
}

#endif

#ifdef RT_USING_SPI3
struct stm32_spi_dma spi3_tx = {
    .dma_stream = DMA1_Stream5,
    .dma_ch = DMA_Channel_0,
    .dma_flag = DMA_FLAG_TCIF5,
    .dma_irq_ch = DMA1_Stream5_IRQn,
};

struct stm32_spi_dma spi3_rx = {
    .dma_stream = DMA1_Stream2,
    .dma_ch = DMA_Channel_0,
    .dma_flag = DMA_FLAG_TCIF2,
    .dma_irq_ch = DMA1_Stream2_IRQn,
};

struct stm32_spi spi3 = {
    .spi = SPI3,
    .bus_name = "spi3",
    .tx_dma = &spi3_tx,
    .rx_dma = &spi3_rx,
};

void DMA1_Stream5_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    stm32_dma_done(&spi3, 1);

    /* leave interrupt */
    rt_interrupt_leave();
}

void DMA1_Stream2_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    stm32_dma_done(&spi3, 0);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

static int stm32_spi_register(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

#ifdef RT_USING_SPI1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1);

    spi1.spi_bus.parent.user_data = &spi1;
    stm32_spi_dma_init(&spi1);
    rt_spi_bus_register(&spi1.spi_bus, spi1.bus_name, &stm_spi_ops);
#endif

#ifdef RT_USING_SPI2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_SPI2);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);

    stm32_spi_dma_init(&spi2);
    spi2.spi_bus.parent.user_data = &spi2;
    rt_spi_bus_register(&spi2.spi_bus, spi2.bus_name, &stm_spi_ops);

#endif

#ifdef RT_USING_SPI3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI3);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI3);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI3);

    stm32_spi_dma_init(&spi3);
    spi3.spi_bus.parent.user_data = &spi3;
    rt_spi_bus_register(&spi3.spi_bus, spi3.bus_name, &stm_spi_ops);

#endif
    return 0;
}
INIT_BOARD_EXPORT(stm32_spi_register);

void stm32_spi_bus_attach(const char *bus_name,                        /* 总线名字 */
                          const char *device_name,                     /* 设备名称 */
                          GPIO_TypeDef *cs_gpiox, uint16_t cs_gpio_pin /* 片选脚 */
)
{
    RT_ASSERT(bus_name != RT_NULL);
    RT_ASSERT(device_name != RT_NULL);

    rt_err_t result;
    struct rt_spi_device *spi_device;
    struct stm32_hw_spi_cs *cs_pin;

    /* initialize the cs pin && select the slave*/
    GPIO_InitTypeDef GPIO_Initure;
    GPIO_Initure.GPIO_Pin = cs_gpio_pin;
    GPIO_Initure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_Initure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Initure.GPIO_OType = GPIO_OType_PP;
    GPIO_Initure.GPIO_PuPd = GPIO_PuPd_UP;

    GPIO_Init(cs_gpiox, &GPIO_Initure);

    /* attach the device to spi bus*/
    spi_device = (struct rt_spi_device *)rt_malloc(sizeof(struct rt_spi_device));
    RT_ASSERT(spi_device != RT_NULL);
    cs_pin = (struct stm32_hw_spi_cs *)rt_malloc(sizeof(struct stm32_hw_spi_cs));
    RT_ASSERT(cs_pin != RT_NULL);
    cs_pin->GPIOx = cs_gpiox;
    cs_pin->GPIO_Pin = cs_gpio_pin;
    CS_Set(cs_pin);

    result = rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin);

    if (result != RT_EOK)
    {
        LOG_E("%s attach to %s faild, %d\n", device_name, bus_name, result);
    }

    RT_ASSERT(result == RT_EOK);

    LOG_D("%s attach to %s done", device_name, bus_name);
}
